﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using Vowei.Web.Models;
using Vowei.Data.Helpers;
using Vowei.Data.Converters.Excel;
using Vowei.Core.Models;
using System.Collections;
using Vowei.Data.Converters;

namespace Vowei.Web.Controllers
{
    public class WizardController : G18nController
    {
        private IVoweiContext _context;
        private IUser _user;

        public WizardController(IVoweiContext context, IUser user)
        {
            _context = context;
            _user = user;
        }

        public ActionResult ImportProjectTasks(Guid id)
        {
            ViewData["ExcelTemplate"] = "Project schedule template.xls";
            var converters = new FormatConverter[] {
                    new WorkItemExcelConverter(_context.TicketStatusManager),
                    new DataConnectionWorkItemExcelConverter(_context.TicketStatusManager)
            };
            return ExecuteWizardStep(id,
                () => CreateImportWizard(SaveImportedProjectData, converters));
        }

        public ActionResult ImportRequirementTasks(Guid id)
        {
            ViewData["ExcelTemplate"] = "Requirement schedule template.xls";
            var converters = new FormatConverter[] {
                    new DataConnectionWorkItemExcelConverter(_context.TicketStatusManager)
            };
            return ExecuteWizardStep(id, () => CreateImportWizard(SaveImportedRequirementData, converters));
        }

        [HttpPost]
        public ActionResult ConfirmImport(FormCollection collection)
        {
            return ExecuteWizardStep(this, null);
        }

        [HttpPost]
        public ActionResult FinishImport(FormCollection collection)
        {
            return ExecuteWizardStep(this, null);
        }

        private IWizardStep CreateImportWizard(Func<object, object, INamedTable> savingFunc, FormatConverter[] converters)
        {
            var firstStep = new GenericWizardStep(w =>
            {
                ViewData["ID"] = (Guid)w.State;
                return View("BeginImport");
            });

            var step = firstStep;

            step = step.NextStep = new GenericWizardStep(w =>
            {
                var controller = w.State as Controller;
                var collection = controller.Request.Form;
                var httpStream = controller.Request.Files["Spreadsheet"].InputStream;
                var stream = new MemoryStream((int)httpStream.Length);
                httpStream.CopyTo(stream);
                var filename = controller.Request.Files["Spreadsheet"].FileName;
                var sheetName = collection["WorksheetName"];
                var pid = Guid.Parse(collection["ID"]);
                var isXlsx = string.Compare(
                    Path.GetExtension(filename), ".xlsx", true) == 0;

                if (isXlsx)
                    throw new NotSupportedException(T("暂时还不支持Excel 2007的XLSX格式，请上传Excel 2003格式的文件！"));
                var tickets = ConvertDataFromExcel(stream, sheetName, converters);
                controller.Session["ImportedData"] = tickets;
                controller.ViewData["ID"] = pid;

                return View("ConfirmImport", tickets);
            });

            step = step.NextStep = new GenericWizardStep(w =>
            {
                var controller = w.State as Controller;
                var collection = controller.Request.Form;
                var pid = Guid.Parse(collection["ID"]);
                var tickets = controller.Session["ImportedData"] as IEnumerable<ITable>;

                try
                {
                    var value = savingFunc(collection["ID"], controller.Session["ImportedData"]);

                    if (value is ICommentable)
                    {
                        var commentable = value as ICommentable;
                        var history = commentable.TrackingChange(
                            string.Format(T("用户从Excel文件里向{0}导入了具体任务信息!"),
                            value.Title), _user);
                        _context.Comments.Add(history);
                    }

                    _context.SaveChanges();

                    return RedirectToAction("Details", EntityHelpers.GetEntityTypeName(value.GetType()), new { id = pid });
                }
                finally
                {
                    controller.Session.Remove("ImportedData");
                }
            });

            return firstStep;
        }

        private Project SaveImportedProjectData(object key, object data)
        {
            var pid = Guid.Parse(key.ToString());
            var tickets = (IEnumerable<ITable>)data;
            var project = _context.Projects.Find(pid);

            if (project != null)
            {
                ImportHelper.ImportDataTo(project, _context, tickets, _user);
                return project;
            }
            else
            {
                throw new InvalidDataException(T("网站中数据库保存的项目对象并不支持从外部导入数据！"));
            }
        }

        private Requirement SaveImportedRequirementData(object key, object data)
        {
            var id = Guid.Parse(key.ToString());
            var tickets = (IEnumerable<ITable>)data;
            var requirement = _context.Requirements.Find(id);

            if (requirement != null)
            {
                ImportHelper.ImportDataTo(requirement, _context, tickets, _user);
                return requirement;
            }
            else
            {
                throw new InvalidDataException(T("网站中数据库保存的需求对象并不支持从外部导入数据！"));
            }
        }
        
        private static object ConvertDataFromExcel(MemoryStream stream, string sheetName, FormatConverter[] converters)
        {
            var converter = converters[0];
            foreach (var c in converters)
            {
                stream.Seek(0, SeekOrigin.Begin);
                if (c.CanConvert(stream))
                {
                    converter = c;
                    break;
                }
            }

            stream.Seek(0, SeekOrigin.Begin);
            var tickets = converter.ConvertFrom(stream);
            return tickets;
        }

        private ActionResult ExecuteWizardStep(object state, Func<IWizardStep> createRouting)
        {
            IWizardStep step = null;
            if (createRouting != null)
            {
                step = createRouting();
                Session["WIZARD_STEP"] = step;
            }
            else
            {
                step = (IWizardStep)Session["WIZARD_STEP"];
            }

            step.State = state;
            var nextStep = step.Next();

            if (nextStep == null)
                Session.Remove("WIZARD_STEP");
            else
                Session["WIZARD_STEP"] = nextStep;

            return step.Result;
        }

    }
}
